﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Com.PhilChuang.Mobile.Apps.LocationSender.Model.Data;
using Com.PhilChuang.Mobile.Apps.LocationSender.Ui.Views;
using Com.PhilChuang.Pmvp.Model.Services;
using Com.PhilChuang.Utils;

namespace Com.PhilChuang.Mobile.Apps.LocationSender.Ui.Presenters
{
	public class SelectFormatPresenter : AbstractLocationSenderAppPresenter<ISelectFormatView>
	{
		#region Constants
		private const String RECIPIENTS = "SelectFormatPresenter.RECIPIENTS";
		private const String FORMAT = "SelectFormatPresenter.FORMAT";
		private const String MESSAGE_SENT = "SelectFormatPresenter.MESSAGE_SENT";
		#endregion

		#region Private members
		private IList<String> m_Recipients;
		private GeoCoordinateFormat m_Format;
		private readonly ITransientAppStateService m_TransientState;
		private bool m_MessageSent = false;
		#endregion

		#region Constructors / Dispose
		public SelectFormatPresenter () : this (AppServiceLocator.Instance.GetImpl<ISelectFormatView> ())
		{
		}

		public SelectFormatPresenter (ISelectFormatView view) : base (view)
		{
			m_TransientState = AppServiceLocator.Instance.GetImpl<ITransientAppStateService> ();
		}
		#endregion

		#region AbstractPresenter implementation
		/// <summary>
		/// Subscribe to View events after the View is registered during Presenter instantiation.
		/// Call base impl as the first step.
		/// </summary>
		protected override void SubscribeToViewEvents ()
		{
			base.SubscribeToViewEvents ();

			View.DoReloadData += OnDoReloadData;
			View.SendMessage += OnSendMessage;
		}

		/// <summary>
		/// Unsubscribes to View events after the View has Closed.
		/// Call base impl as the first step.
		/// </summary>
		protected override void UnsubscribeFromViewEvents ()
		{
			base.UnsubscribeFromViewEvents ();

			View.DoReloadData -= OnDoReloadData;
			View.SendMessage -= OnSendMessage;
		}

		/// <summary>
		/// Updates the View with Presenter data.
		/// Call base impl as the last step.
		/// </summary>
		protected override void UpdateToView ()
		{
			View.Recipients = m_Recipients;
			View.Format = m_Format;

			base.UpdateToView ();
		}

		protected override void UpdateFromView ()
		{
			m_Format = View.Format;

			base.UpdateFromView ();
		}

		/// <summary>
		/// Fires when the View is trying to Close.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		protected override void OnDoClose (object sender, System.ComponentModel.CancelEventArgs e)
		{
			// if we're here, we're navigating backwards
			ClearTransientState ();
		}

		/// <summary>
		/// Fires when the View is Closed.
		/// Base impl calls Dispose.
		/// Call base impl as the last step.
		/// </summary>
		protected override void OnClosed ()
		{
			if (m_MessageSent)
				m_TransientState[MESSAGE_SENT] = true;
			base.OnClosed ();
		}

		public override void Show ()
		{
			// prevent this method from being called, since we want them to use the Show (recipients) method
			throw new InvalidOperationException ();
		}
		#endregion

		#region AbstractAppPresenter implementation
		/// <summary>
		/// Overridable method to do work when the App is suspending.
		/// Call base impl as the first step.
		/// </summary>
		protected override void DoAppSuspendingWork ()
		{
			base.DoAppSuspendingWork ();
			UpdateFromView ();
			SaveTransientState ();
		}
		#endregion

		#region Event handlers
		private void OnDoReloadData ()
		{
			m_IsReloadingDataOnViewLoaded = true;
			ExecuteAsync (() => {
			              	m_Recipients = new List<String> ();
			              	LoadTransientState ();
			              	RefreshDataAndUpdateToView ();
			              	m_IsReloadingDataOnViewLoaded = false;
			              	View.EnableAllControls (true);
			              });
		}

		private void OnSendMessage ()
		{
			UpdateFromView ();
			m_MessageSent = true;
			m_App.SendMessage (m_Recipients, m_Format);
		}

		protected override void OnViewLoaded ()
		{
			Object messageSent;
			if (m_TransientState.TryGetValue (MESSAGE_SENT, out messageSent) && (bool) messageSent)
			{
				View.EnableAllControls (false);
				ClearTransientState ();
				ReturnToPresenter = typeof (WelcomePresenter);
			}

			base.OnViewLoaded ();
		}
		#endregion

		#region Functionality
		public void Show (IList<String> recipients)
		{
			recipients.ThrowIfNull ("recipients");
			m_Recipients = recipients;

			View.Show ();
		}
		#endregion

		#region helpers
		private void SaveTransientState ()
		{
			m_TransientState[RECIPIENTS] = m_Recipients.Print (";");
			m_TransientState[FORMAT] = m_Format;
		}

		private void LoadTransientState ()
		{
			if (m_TransientState.ContainsKey (RECIPIENTS))
			{
				var recips = m_TransientState[RECIPIENTS] as String;
				if (!recips.IsNullOrEmptyOrBlank ())
				{
					m_Recipients = recips.Split (';');
				}
			}
			if (m_TransientState.ContainsKey (FORMAT))
			{
				var formatStr = m_TransientState[FORMAT] as String;
				if (!formatStr.IsNullOrEmptyOrBlank ())
				{
					Extensions.EnumTryParse (formatStr, ref m_Format);
				}
			}
		}

		private void ClearTransientState ()
		{
			if (m_TransientState.ContainsKey (RECIPIENTS))
			{
				m_TransientState[RECIPIENTS] = null;
				m_TransientState.Remove (RECIPIENTS);
			}
			if (m_TransientState.ContainsKey (FORMAT))
			{
				m_TransientState[FORMAT] = null;
				m_TransientState.Remove (FORMAT);
			}
			if (m_TransientState.ContainsKey (MESSAGE_SENT))
			{
				m_TransientState[MESSAGE_SENT] = null;
				m_TransientState.Remove (MESSAGE_SENT);
			}
		}
		#endregion
	}
}
